{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "ef2140bb",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-23T02:27:44.899757Z",
     "iopub.status.busy": "2025-02-23T02:27:44.898474Z",
     "iopub.status.idle": "2025-02-23T02:27:45.444314Z",
     "shell.execute_reply": "2025-02-23T02:27:45.443202Z"
    }
   },
   "outputs": [
    {
     "ename": "ModuleNotFoundError",
     "evalue": "No module named 'pgmpy'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mModuleNotFoundError\u001b[0m                       Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[1], line 3\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpandas\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mas\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpd\u001b[39;00m\n\u001b[1;32m      2\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mnumpy\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mas\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mnp\u001b[39;00m\n\u001b[0;32m----> 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpgmpy\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mmodels\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m BayesianNetwork\n\u001b[1;32m      4\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpgmpy\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mfactors\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdiscrete\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m TabularCPD\n\u001b[1;32m      5\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpgmpy\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mestimators\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m MaximumLikelihoodEstimator, BayesianEstimator\n",
      "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'pgmpy'"
     ]
    }
   ],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "from pgmpy.models import BayesianNetwork\n",
    "from pgmpy.factors.discrete import TabularCPD\n",
    "from pgmpy.estimators import MaximumLikelihoodEstimator, BayesianEstimator\n",
    "import matplotlib.pyplot as plt\n",
    "import networkx as nx\n",
    "from sklearn.preprocessing import LabelEncoder\n",
    "\n",
    "# Load the Titanic dataset\n",
    "url = \"https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv\"\n",
    "df = pd.read_csv(url)\n",
    "\n",
    "# Data preprocessing\n",
    "# Fill missing values\n",
    "df['Age'].fillna(df['Age'].median(), inplace=True)\n",
    "df['Embarked'].fillna(df['Embarked'].mode()[0], inplace=True)\n",
    "df['Fare'].fillna(df['Fare'].median(), inplace=True)\n",
    "\n",
    "# Create age groups\n",
    "df['AgeGroup'] = pd.cut(df['Age'], bins=[0, 12, 30, 50, 100], labels=['Child', 'Young', 'Adult', 'Elder'])\n",
    "\n",
    "# Select relevant features\n",
    "features = ['Pclass', 'Sex', 'AgeGroup', 'Survived']\n",
    "df_bn = df[features].copy()\n",
    "\n",
    "# Label encoding for categorical variables\n",
    "le = LabelEncoder()\n",
    "for col in df_bn.columns:\n",
    "    df_bn[col] = le.fit_transform(df_bn[col])\n",
    "\n",
    "# Create Bayesian Network structure\n",
    "model = BayesianNetwork([\n",
    "    ('Pclass', 'Survived'),\n",
    "    ('Sex', 'Survived'),\n",
    "    ('AgeGroup', 'Survived')\n",
    "])\n",
    "\n",
    "# Fit the model using Maximum Likelihood Estimation\n",
    "mle = MaximumLikelihoodEstimator(model=model, data=df_bn)\n",
    "\n",
    "# Calculate CPDs (Conditional Probability Distributions)\n",
    "cpd_pclass = mle.estimate_cpd(node='Pclass')\n",
    "cpd_sex = mle.estimate_cpd(node='Sex')\n",
    "cpd_age = mle.estimate_cpd(node='AgeGroup')\n",
    "cpd_survived = mle.estimate_cpd(node='Survived')\n",
    "\n",
    "# Add CPDs to model\n",
    "model.add_cpds(cpd_pclass, cpd_sex, cpd_age, cpd_survived)\n",
    "\n",
    "# Check if the model is valid\n",
    "print(\"Model is valid:\", model.check_model())\n",
    "\n",
    "# Visualize the network\n",
    "plt.figure(figsize=(10, 6))\n",
    "nx.draw(model, with_labels=True, node_color='lightblue', \n",
    "        node_size=2000, font_size=16, font_weight='bold',\n",
    "        arrows=True, edge_color='gray')\n",
    "plt.title(\"Titanic Survival Bayesian Network\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "df95693b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-23T02:28:10.195919Z",
     "iopub.status.busy": "2025-02-23T02:28:10.195478Z",
     "iopub.status.idle": "2025-02-23T02:28:18.262340Z",
     "shell.execute_reply": "2025-02-23T02:28:18.261119Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-02-22 18:28:17.570 | INFO     | metagpt.tools.libs.terminal:run:260 - No more output after 3s, detached from current tab and switched to a new tab\n"
     ]
    },
    {
     "ename": "ModuleNotFoundError",
     "evalue": "No module named 'pgmpy'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mModuleNotFoundError\u001b[0m                       Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[2], line 9\u001b[0m\n\u001b[1;32m      7\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpandas\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mas\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpd\u001b[39;00m\n\u001b[1;32m      8\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mnumpy\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mas\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mnp\u001b[39;00m\n\u001b[0;32m----> 9\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpgmpy\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mmodels\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m BayesianNetwork\n\u001b[1;32m     10\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpgmpy\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mfactors\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdiscrete\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m TabularCPD\n\u001b[1;32m     11\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpgmpy\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mestimators\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m MaximumLikelihoodEstimator, BayesianEstimator\n",
      "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'pgmpy'"
     ]
    }
   ],
   "source": [
    "from metagpt.tools.libs.terminal import Terminal\n",
    "\n",
    "# Install required package\n",
    "terminal = Terminal()\n",
    "await terminal.run('pip install pgmpy')\n",
    "\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "from pgmpy.models import BayesianNetwork\n",
    "from pgmpy.factors.discrete import TabularCPD\n",
    "from pgmpy.estimators import MaximumLikelihoodEstimator, BayesianEstimator\n",
    "from pgmpy.inference import VariableElimination\n",
    "import matplotlib.pyplot as plt\n",
    "import networkx as nx\n",
    "from sklearn.preprocessing import LabelEncoder\n",
    "\n",
    "# Load the Titanic dataset\n",
    "url = \"https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv\"\n",
    "df = pd.read_csv(url)\n",
    "\n",
    "# Data preprocessing\n",
    "# Fill missing values\n",
    "df['Age'].fillna(df['Age'].median(), inplace=True)\n",
    "df['Embarked'].fillna(df['Embarked'].mode()[0], inplace=True)\n",
    "df['Fare'].fillna(df['Fare'].median(), inplace=True)\n",
    "\n",
    "# Create age groups\n",
    "df['AgeGroup'] = pd.cut(df['Age'], bins=[0, 12, 30, 50, 100], labels=['Child', 'Young', 'Adult', 'Elder'])\n",
    "\n",
    "# Select relevant features\n",
    "features = ['Pclass', 'Sex', 'AgeGroup', 'Survived']\n",
    "df_bn = df[features].copy()\n",
    "\n",
    "# Label encoding for categorical variables\n",
    "le_dict = {}\n",
    "for col in df_bn.columns:\n",
    "    le = LabelEncoder()\n",
    "    df_bn[col] = le.fit_transform(df_bn[col])\n",
    "    le_dict[col] = le\n",
    "\n",
    "# Create Bayesian Network structure\n",
    "model = BayesianNetwork([\n",
    "    ('Pclass', 'Survived'),\n",
    "    ('Sex', 'Survived'),\n",
    "    ('AgeGroup', 'Survived')\n",
    "])\n",
    "\n",
    "# Fit the model using Maximum Likelihood Estimation\n",
    "mle = MaximumLikelihoodEstimator(model=model, data=df_bn)\n",
    "\n",
    "# Calculate CPDs (Conditional Probability Distributions)\n",
    "cpd_pclass = mle.estimate_cpd(node='Pclass')\n",
    "cpd_sex = mle.estimate_cpd(node='Sex')\n",
    "cpd_age = mle.estimate_cpd(node='AgeGroup')\n",
    "cpd_survived = mle.estimate_cpd(node='Survived')\n",
    "\n",
    "# Add CPDs to model\n",
    "model.add_cpds(cpd_pclass, cpd_sex, cpd_age, cpd_survived)\n",
    "\n",
    "# Check if the model is valid\n",
    "print(\"Model is valid:\", model.check_model())\n",
    "\n",
    "# Visualize the network\n",
    "plt.figure(figsize=(10, 6))\n",
    "nx.draw(model, with_labels=True, node_color='lightblue', \n",
    "        node_size=2000, font_size=16, font_weight='bold',\n",
    "        arrows=True, edge_color='gray')\n",
    "plt.title(\"Titanic Survival Bayesian Network\")\n",
    "plt.show()\n",
    "\n",
    "# Perform inference\n",
    "inference = VariableElimination(model)\n",
    "\n",
    "# Example profiles\n",
    "profiles = [\n",
    "    {'Pclass': 1, 'Sex': le_dict['Sex'].transform(['female'])[0], 'AgeGroup': le_dict['AgeGroup'].transform(['Young'])[0]},\n",
    "    {'Pclass': 3, 'Sex': le_dict['Sex'].transform(['male'])[0], 'AgeGroup': le_dict['AgeGroup'].transform(['Adult'])[0]},\n",
    "    {'Pclass': 2, 'Sex': le_dict['Sex'].transform(['female'])[0], 'AgeGroup': le_dict['AgeGroup'].transform(['Child'])[0]}\n",
    "]\n",
    "\n",
    "# Calculate survival probabilities for each profile\n",
    "for i, profile in enumerate(profiles, 1):\n",
    "    q = inference.query(variables=['Survived'], evidence=profile)\n",
    "    print(f\"\\nProfile {i} Survival Probability:\")\n",
    "    print(f\"Class: {profile['Pclass']}, \")\n",
    "    print(f\"Sex: {le_dict['Sex'].inverse_transform([profile['Sex']])[0]}, \")\n",
    "    print(f\"Age Group: {le_dict['AgeGroup'].inverse_transform([profile['AgeGroup']])[0]}\")\n",
    "    print(f\"Survival Probability: {q.values[1]:.2%}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "075062ed",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-23T02:28:53.254823Z",
     "iopub.status.busy": "2025-02-23T02:28:53.254052Z",
     "iopub.status.idle": "2025-02-23T02:29:01.024893Z",
     "shell.execute_reply": "2025-02-23T02:29:01.023839Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "The command is running in detach at tab 00, currently with output: Collecting pgmpy\n",
      "  Downloading pgmpy-0.1.26-py3-none-any.whl (2.0 MB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.0/2.0 MB\u001b[0m \u001b[31m143.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[?25hRequirement already satisfied: networkx in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from pgmpy) (3.2.1)\n",
      "Requirement already satisfied: scikit-learn in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from pgmpy) (1.3.2)\n",
      "Requirement already satisfied: opt-einsum in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from pgmpy) (3.3.0)\n",
      "Requirement already satisfied: torch in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from pgmpy) (2.5.1)\n",
      "Requirement already satisfied: tqdm in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from pgmpy) (4.66.2)\n",
      "Requirement already satisfied: joblib in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from pgmpy) (1.4.2)\n",
      "Requirement already satisfied: scipy in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from pgmpy) (1.15.1)\n",
      "Requirement already satisfied: pyparsing in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from pgmpy) (3.2.1)\n",
      "Requirement already satisfied: pandas in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from pgmpy) (2.1.1)\n",
      "Requirement already satisfied: xgboost in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from pgmpy) (2.1.3)\n",
      "Requirement already satisfied: google-generativeai in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from pgmpy) (0.4.1)\n",
      "Requirement already satisfied: numpy in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from pgmpy) (1.24.3)\n",
      "Requirement already satisfied: statsmodels in /data/.cache/python/lib/python3.10/site-packages (from pgmpy) (0.14.4)\n",
      "Requirement already satisfied: typing-extensions in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from google-generativeai->pgmpy) (4.9.0)\n",
      "Requirement already satisfied: google-ai-generativelanguage==0.4.0 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from google-generativeai->pgmpy) (0.4.0)\n",
      "Requirement already satisfied: google-auth>=2.15.0 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from google-generativeai->pgmpy) (2.38.0)\n",
      "Requirement already satisfied: protobuf in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from google-generativeai->pgmpy) (3.19.6)\n",
      "Requirement already satisfied: pydantic in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from google-generativeai->pgmpy) (2.5.3)\n",
      "Requirement already satisfied: google-api-core in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from google-generativeai->pgmpy) (2.24.1)\n",
      "Requirement already satisfied: proto-plus<2.0.0dev,>=1.22.3 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from google-ai-generativelanguage==0.4.0->google-generativeai->pgmpy) (1.26.0)\n",
      "Requirement already satisfied: tzdata>=2022.1 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from pandas->pgmpy) (2025.1)\n",
      "Requirement already satisfied: pytz>=2020.1 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from pandas->pgmpy) (2025.1)\n",
      "Requirement already satisfied: python-dateutil>=2.8.2 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from pandas->pgmpy) (2.9.0.post0)\n",
      "Requirement already satisfied: threadpoolctl>=2.0.0 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from scikit-learn->pgmpy) (3.5.0)\n",
      "Requirement already satisfied: patsy>=0.5.6 in /data/.cache/python/lib/python3.10/site-packages (from statsmodels->pgmpy) (1.0.1)\n",
      "Requirement already satisfied: packaging>=21.3 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from statsmodels->pgmpy) (23.0)\n",
      "Requirement already satisfied: fsspec in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from torch->pgmpy) (2025.2.0)\n",
      "Requirement already satisfied: nvidia-cufft-cu12==11.2.1.3 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from torch->pgmpy) (11.2.1.3)\n",
      "Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.4.127 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from torch->pgmpy) (12.4.127)\n",
      "Requirement already satisfied: nvidia-cuda-cupti-cu12==12.4.127 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from torch->pgmpy) (12.4.127)\n",
      "Requirement already satisfied: nvidia-cuda-runtime-cu12==12.4.127 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from torch->pgmpy) (12.4.127)\n",
      "Requirement already satisfied: nvidia-nvtx-cu12==12.4.127 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from torch->pgmpy) (12.4.127)\n",
      "Requirement already satisfied: triton==3.1.0 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from torch->pgmpy) (3.1.0)\n",
      "Requirement already satisfied: nvidia-curand-cu12==10.3.5.147 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from torch->pgmpy) (10.3.5.147)\n",
      "Requirement already satisfied: nvidia-cusolver-cu12==11.6.1.9 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from torch->pgmpy) (11.6.1.9)\n",
      "Requirement already satisfied: nvidia-nvjitlink-cu12==12.4.127 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from torch->pgmpy) (12.4.127)\n",
      "Requirement already satisfied: jinja2 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from torch->pgmpy) (3.1.5)\n",
      "Requirement already satisfied: nvidia-cusparse-cu12==12.3.1.170 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from torch->pgmpy) (12.3.1.170)\n",
      "Requirement already satisfied: sympy==1.13.1 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from torch->pgmpy) (1.13.1)\n",
      "Requirement already satisfied: nvidia-cudnn-cu12==9.1.0.70 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from torch->pgmpy) (9.1.0.70)\n",
      "Requirement already satisfied: nvidia-nccl-cu12==2.21.5 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from torch->pgmpy) (2.21.5)\n",
      "Requirement already satisfied: filelock in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from torch->pgmpy) (3.17.0)\n",
      "Requirement already satisfied: nvidia-cublas-cu12==12.4.5.8 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from torch->pgmpy) (12.4.5.8)\n",
      "Requirement already satisfied: mpmath<1.4,>=1.1.0 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from sympy==1.13.1->torch->pgmpy) (1.3.0)\n",
      "Requirement already satisfied: pyasn1-modules>=0.2.1 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from google-auth>=2.15.0->google-generativeai->pgmpy) (0.4.1)\n",
      "Requirement already satisfied: rsa<5,>=3.1.4 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from google-auth>=2.15.0->google-generativeai->pgmpy) (4.9)\n",
      "Requirement already satisfied: cachetools<6.0,>=2.0.0 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from google-auth>=2.15.0->google-generativeai->pgmpy) (5.5.1)\n",
      "Requirement already satisfied: six>=1.5 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from python-dateutil>=2.8.2->pandas->pgmpy) (1.16.0)\n",
      "Requirement already satisfied: requests<3.0.0.dev0,>=2.18.0 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from google-api-core->google-generativeai->pgmpy) (2.32.3)\n",
      "Requirement already satisfied: googleapis-common-protos<2.0.dev0,>=1.56.2 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from google-api-core->google-generativeai->pgmpy) (1.63.1)\n",
      "Requirement already satisfied: MarkupSafe>=2.0 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from jinja2->torch->pgmpy) (3.0.2)\n",
      "Requirement already satisfied: annotated-types>=0.4.0 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from pydantic->google-generativeai->pgmpy) (0.7.0)\n",
      "Requirement already satisfied: pydantic-core==2.14.6 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from pydantic->google-generativeai->pgmpy) (2.14.6)\n",
      "Requirement already satisfied: grpcio<2.0dev,>=1.33.2 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from google-api-core->google-generativeai->pgmpy) (1.70.0)\n",
      "Requirement already satisfied: grpcio-status<2.0.dev0,>=1.33.2 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from google-api-core->google-generativeai->pgmpy) (1.48.2)\n",
      "Requirement already satisfied: pyasn1<0.7.0,>=0.4.6 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from pyasn1-modules>=0.2.1->google-auth>=2.15.0->google-generativeai->pgmpy) (0.6.1)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from requests<3.0.0.dev0,>=2.18.0->google-api-core->google-generativeai->pgmpy) (3.4)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from requests<3.0.0.dev0,>=2.18.0->google-api-core->google-generativeai->pgmpy) (2025.1.31)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from requests<3.0.0.dev0,>=2.18.0->google-api-core->google-generativeai->pgmpy) (2.0.4)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in /opt/conda/envs/mgx-chat/lib/python3.10/site-packages (from requests<3.0.0.dev0,>=2.18.0->google-api-core->google-generativeai->pgmpy) (1.26.15)\n",
      "Installing collected packages: pgmpy\n",
      "\n",
      "New tab info: [Tab 01 created. Switched to tab 01, pwd is /data/chats/0ii6o/workspace, the tab has new output: ]\n",
      "Note: You may operate on the new tab, or switch back to the detached tab 00 to get incremental output. If you successfully launch a service at the detached tab 00, you can also preview it (tab_id: 00).\n",
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-02-22 18:29:01.003 | INFO     | metagpt.tools.libs.terminal:run:260 - No more output after 3s, detached from current tab and switched to a new tab\n"
     ]
    }
   ],
   "source": [
    "from metagpt.tools.libs.terminal import Terminal\n",
    "\n",
    "# Install required packages\n",
    "terminal = Terminal()\n",
    "install_cmd = \"pip install --no-cache-dir pgmpy\"\n",
    "result = await terminal.run(install_cmd)\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "6318dfed",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-23T02:29:35.041806Z",
     "iopub.status.busy": "2025-02-23T02:29:35.041240Z",
     "iopub.status.idle": "2025-02-23T02:29:35.100349Z",
     "shell.execute_reply": "2025-02-23T02:29:35.098845Z"
    }
   },
   "outputs": [
    {
     "ename": "ModuleNotFoundError",
     "evalue": "No module named 'pgmpy'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mModuleNotFoundError\u001b[0m                       Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[4], line 3\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpandas\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mas\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpd\u001b[39;00m\n\u001b[1;32m      2\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mnumpy\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mas\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mnp\u001b[39;00m\n\u001b[0;32m----> 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpgmpy\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mmodels\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m BayesianNetwork\n\u001b[1;32m      4\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpgmpy\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mfactors\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdiscrete\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m TabularCPD\n\u001b[1;32m      5\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpgmpy\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01minference\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m VariableElimination\n",
      "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'pgmpy'"
     ]
    }
   ],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "from pgmpy.models import BayesianNetwork\n",
    "from pgmpy.factors.discrete import TabularCPD\n",
    "from pgmpy.inference import VariableElimination\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "from sklearn.preprocessing import LabelEncoder\n",
    "\n",
    "# Load Titanic dataset\n",
    "url = \"https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv\"\n",
    "df = pd.read_csv(url)\n",
    "\n",
    "# Preprocess the data\n",
    "# Handle missing values\n",
    "df['Age'].fillna(df['Age'].median(), inplace=True)\n",
    "df['Embarked'].fillna(df['Embarked'].mode()[0], inplace=True)\n",
    "\n",
    "# Create age groups\n",
    "df['AgeGroup'] = pd.cut(df['Age'], bins=[0, 12, 30, 50, 100], labels=['Child', 'Young', 'Adult', 'Elder'])\n",
    "\n",
    "# Select features for the Bayesian Network\n",
    "features = ['Pclass', 'Sex', 'AgeGroup', 'Survived']\n",
    "df_model = df[features].copy()\n",
    "\n",
    "# Label encode categorical variables\n",
    "le_dict = {}\n",
    "for col in df_model.columns:\n",
    "    le = LabelEncoder()\n",
    "    df_model[col] = le.fit_transform(df_model[col])\n",
    "    le_dict[col] = le\n",
    "\n",
    "# Create Bayesian Network structure\n",
    "model = BayesianNetwork([\n",
    "    ('Pclass', 'Survived'),\n",
    "    ('Sex', 'Survived'),\n",
    "    ('AgeGroup', 'Survived')\n",
    "])\n",
    "\n",
    "# Calculate CPDs (Conditional Probability Distributions)\n",
    "# CPD for Pclass (root node)\n",
    "cpd_pclass = TabularCPD(variable='Pclass', variable_card=3,\n",
    "                        values=[df_model['Pclass'].value_counts(normalize=True).values])\n",
    "\n",
    "# CPD for Sex (root node)\n",
    "cpd_sex = TabularCPD(variable='Sex', variable_card=2,\n",
    "                     values=[df_model['Sex'].value_counts(normalize=True).values])\n",
    "\n",
    "# CPD for AgeGroup (root node)\n",
    "cpd_age = TabularCPD(variable='AgeGroup', variable_card=4,\n",
    "                     values=[df_model['AgeGroup'].value_counts(normalize=True).values])\n",
    "\n",
    "# CPD for Survived (dependent node)\n",
    "survival_data = []\n",
    "for pclass in range(3):\n",
    "    for sex in range(2):\n",
    "        for age in range(4):\n",
    "            mask = (df_model['Pclass'] == pclass) & (df_model['Sex'] == sex) & (df_model['AgeGroup'] == age)\n",
    "            if mask.any():\n",
    "                prob_survival = df_model[mask]['Survived'].mean()\n",
    "            else:\n",
    "                prob_survival = 0.5\n",
    "            survival_data.append([1-prob_survival, prob_survival])\n",
    "\n",
    "cpd_survived = TabularCPD(\n",
    "    variable='Survived',\n",
    "    variable_card=2,\n",
    "    values=np.array(survival_data).T,\n",
    "    evidence=['Pclass', 'Sex', 'AgeGroup'],\n",
    "    evidence_card=[3, 2, 4]\n",
    ")\n",
    "\n",
    "# Add CPDs to model\n",
    "model.add_cpds(cpd_pclass, cpd_sex, cpd_age, cpd_survived)\n",
    "\n",
    "# Check if the model is valid\n",
    "model.check_model()\n",
    "\n",
    "# Create inference object\n",
    "inference = VariableElimination(model)\n",
    "\n",
    "# Visualize network structure\n",
    "plt.figure(figsize=(10, 6))\n",
    "pos = {\n",
    "    'Pclass': (0, 0),\n",
    "    'Sex': (1, 0),\n",
    "    'AgeGroup': (2, 0),\n",
    "    'Survived': (1, -1)\n",
    "}\n",
    "model.draw(pos=pos)\n",
    "plt.title(\"Titanic Survival Bayesian Network\")\n",
    "plt.show()\n",
    "\n",
    "# Example inference for different passenger profiles\n",
    "def predict_survival(pclass, sex, age_group):\n",
    "    evidence = {\n",
    "        'Pclass': le_dict['Pclass'].transform([pclass])[0],\n",
    "        'Sex': le_dict['Sex'].transform([sex])[0],\n",
    "        'AgeGroup': le_dict['AgeGroup'].transform([age_group])[0]\n",
    "    }\n",
    "    result = inference.query(variables=['Survived'], evidence=evidence)\n",
    "    return result.values[1]  # Probability of survival\n",
    "\n",
    "# Example predictions\n",
    "print(\"\\nSurvival Probability Examples:\")\n",
    "examples = [\n",
    "    ('1st', 'female', 'Young'),\n",
    "    ('3rd', 'male', 'Adult'),\n",
    "    ('2nd', 'female', 'Child'),\n",
    "    ('1st', 'male', 'Elder')\n",
    "]\n",
    "\n",
    "for pclass, sex, age_group in examples:\n",
    "    prob = predict_survival(pclass, sex, age_group)\n",
    "    print(f\"Passenger (Class: {pclass}, Sex: {sex}, Age: {age_group}) - Survival Probability: {prob:.2%}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "0ec5551e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-23T02:30:26.382747Z",
     "iopub.status.busy": "2025-02-23T02:30:26.382201Z",
     "iopub.status.idle": "2025-02-23T02:30:31.441466Z",
     "shell.execute_reply": "2025-02-23T02:30:31.440057Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Waiting for pgmpy installation to complete...\n"
     ]
    },
    {
     "ename": "ModuleNotFoundError",
     "evalue": "No module named 'pgmpy'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mModuleNotFoundError\u001b[0m                       Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[5], line 15\u001b[0m\n\u001b[1;32m     12\u001b[0m     time\u001b[38;5;241m.\u001b[39msleep(\u001b[38;5;241m5\u001b[39m)  \u001b[38;5;66;03m# Give some time for the previous installation to finish\u001b[39;00m\n\u001b[1;32m     14\u001b[0m \u001b[38;5;66;03m# Now import required packages\u001b[39;00m\n\u001b[0;32m---> 15\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpgmpy\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mmodels\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m BayesianNetwork\n\u001b[1;32m     16\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpgmpy\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mfactors\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdiscrete\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m TabularCPD\n\u001b[1;32m     17\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpgmpy\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01minference\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m VariableElimination\n",
      "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'pgmpy'"
     ]
    }
   ],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import time\n",
    "from metagpt.tools.libs.terminal import Terminal\n",
    "\n",
    "# Verify pgmpy installation and install if needed\n",
    "terminal = Terminal()\n",
    "try:\n",
    "    import pgmpy\n",
    "except ImportError:\n",
    "    print(\"Waiting for pgmpy installation to complete...\")\n",
    "    time.sleep(5)  # Give some time for the previous installation to finish\n",
    "    \n",
    "# Now import required packages\n",
    "from pgmpy.models import BayesianNetwork\n",
    "from pgmpy.factors.discrete import TabularCPD\n",
    "from pgmpy.inference import VariableElimination\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "from sklearn.preprocessing import LabelEncoder\n",
    "\n",
    "# Load Titanic dataset\n",
    "url = \"https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv\"\n",
    "df = pd.read_csv(url)\n",
    "\n",
    "# Preprocess the data\n",
    "# Handle missing values\n",
    "df['Age'].fillna(df['Age'].median(), inplace=True)\n",
    "df['Embarked'].fillna(df['Embarked'].mode()[0], inplace=True)\n",
    "\n",
    "# Create age groups\n",
    "df['AgeGroup'] = pd.cut(df['Age'], bins=[0, 12, 30, 50, 100], labels=['Child', 'Young', 'Adult', 'Elder'])\n",
    "\n",
    "# Select features for the Bayesian Network\n",
    "features = ['Pclass', 'Sex', 'AgeGroup', 'Survived']\n",
    "df_model = df[features].copy()\n",
    "\n",
    "# Label encode categorical variables\n",
    "le_dict = {}\n",
    "for col in df_model.columns:\n",
    "    le = LabelEncoder()\n",
    "    df_model[col] = le.fit_transform(df_model[col])\n",
    "    le_dict[col] = le\n",
    "\n",
    "# Create Bayesian Network structure\n",
    "model = BayesianNetwork([\n",
    "    ('Pclass', 'Survived'),\n",
    "    ('Sex', 'Survived'),\n",
    "    ('AgeGroup', 'Survived')\n",
    "])\n",
    "\n",
    "# Calculate CPDs (Conditional Probability Distributions)\n",
    "cpd_pclass = TabularCPD(variable='Pclass', variable_card=3,\n",
    "                        values=[df_model['Pclass'].value_counts(normalize=True).values])\n",
    "\n",
    "cpd_sex = TabularCPD(variable='Sex', variable_card=2,\n",
    "                     values=[df_model['Sex'].value_counts(normalize=True).values])\n",
    "\n",
    "cpd_age = TabularCPD(variable='AgeGroup', variable_card=4,\n",
    "                     values=[df_model['AgeGroup'].value_counts(normalize=True).values])\n",
    "\n",
    "# Calculate survival probabilities\n",
    "survival_data = []\n",
    "for pclass in range(3):\n",
    "    for sex in range(2):\n",
    "        for age in range(4):\n",
    "            mask = (df_model['Pclass'] == pclass) & (df_model['Sex'] == sex) & (df_model['AgeGroup'] == age)\n",
    "            if mask.any():\n",
    "                prob_survival = df_model[mask]['Survived'].mean()\n",
    "            else:\n",
    "                prob_survival = 0.5\n",
    "            survival_data.append([1-prob_survival, prob_survival])\n",
    "\n",
    "cpd_survived = TabularCPD(\n",
    "    variable='Survived',\n",
    "    variable_card=2,\n",
    "    values=np.array(survival_data).T,\n",
    "    evidence=['Pclass', 'Sex', 'AgeGroup'],\n",
    "    evidence_card=[3, 2, 4]\n",
    ")\n",
    "\n",
    "# Add CPDs to model and check\n",
    "model.add_cpds(cpd_pclass, cpd_sex, cpd_age, cpd_survived)\n",
    "model.check_model()\n",
    "\n",
    "# Create inference engine\n",
    "inference = VariableElimination(model)\n",
    "\n",
    "# Visualize network\n",
    "plt.figure(figsize=(10, 6))\n",
    "pos = {\n",
    "    'Pclass': (0, 0),\n",
    "    'Sex': (1, 0),\n",
    "    'AgeGroup': (2, 0),\n",
    "    'Survived': (1, -1)\n",
    "}\n",
    "model.draw(pos=pos)\n",
    "plt.title(\"Titanic Survival Bayesian Network\")\n",
    "plt.show()\n",
    "\n",
    "# Function for survival prediction\n",
    "def predict_survival(pclass, sex, age_group):\n",
    "    evidence = {\n",
    "        'Pclass': le_dict['Pclass'].transform([pclass])[0],\n",
    "        'Sex': le_dict['Sex'].transform([sex])[0],\n",
    "        'AgeGroup': le_dict['AgeGroup'].transform([age_group])[0]\n",
    "    }\n",
    "    result = inference.query(variables=['Survived'], evidence=evidence)\n",
    "    return result.values[1]\n",
    "\n",
    "# Example predictions\n",
    "print(\"\\nSurvival Probability Examples:\")\n",
    "examples = [\n",
    "    ('1st', 'female', 'Young'),\n",
    "    ('3rd', 'male', 'Adult'),\n",
    "    ('2nd', 'female', 'Child'),\n",
    "    ('1st', 'male', 'Elder')\n",
    "]\n",
    "\n",
    "for pclass, sex, age_group in examples:\n",
    "    prob = predict_survival(pclass, sex, age_group)\n",
    "    print(f\"Passenger (Class: {pclass}, Sex: {sex}, Age: {age_group}) - Survival Probability: {prob:.2%}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "678a3e78",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-23T02:31:04.113147Z",
     "iopub.status.busy": "2025-02-23T02:31:04.112202Z",
     "iopub.status.idle": "2025-02-23T02:31:17.303829Z",
     "shell.execute_reply": "2025-02-23T02:31:17.302755Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Retry 1/3 - Waiting for installation...\n",
      "Retry 2/3 - Waiting for installation...\n"
     ]
    },
    {
     "ename": "ImportError",
     "evalue": "Failed to install pgmpy after multiple attempts",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mModuleNotFoundError\u001b[0m                       Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[6], line 15\u001b[0m\n\u001b[1;32m     14\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 15\u001b[0m     \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpgmpy\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mmodels\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m BayesianNetwork\n\u001b[1;32m     16\u001b[0m     \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpgmpy\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mfactors\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdiscrete\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m TabularCPD\n",
      "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'pgmpy'",
      "\nDuring handling of the above exception, another exception occurred:\n",
      "\u001b[0;31mImportError\u001b[0m                               Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[6], line 25\u001b[0m\n\u001b[1;32m     23\u001b[0m             time\u001b[38;5;241m.\u001b[39msleep(\u001b[38;5;241m3\u001b[39m)\n\u001b[1;32m     24\u001b[0m         \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m---> 25\u001b[0m             \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mImportError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mFailed to install pgmpy after multiple attempts\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m     27\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mmatplotlib\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mpyplot\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mas\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mplt\u001b[39;00m\n\u001b[1;32m     28\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mseaborn\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mas\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01msns\u001b[39;00m\n",
      "\u001b[0;31mImportError\u001b[0m: Failed to install pgmpy after multiple attempts"
     ]
    }
   ],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import time\n",
    "from metagpt.tools.libs.terminal import Terminal\n",
    "\n",
    "# Install and verify pgmpy installation\n",
    "terminal = Terminal()\n",
    "await terminal.run('pip install --no-cache-dir pgmpy')\n",
    "time.sleep(2)  # Wait for installation to complete\n",
    "\n",
    "# Verify installation with a retry mechanism\n",
    "max_retries = 3\n",
    "for attempt in range(max_retries):\n",
    "    try:\n",
    "        from pgmpy.models import BayesianNetwork\n",
    "        from pgmpy.factors.discrete import TabularCPD\n",
    "        from pgmpy.inference import VariableElimination\n",
    "        print('Successfully imported pgmpy')\n",
    "        break\n",
    "    except ImportError:\n",
    "        if attempt < max_retries - 1:\n",
    "            print(f'Retry {attempt + 1}/{max_retries} - Waiting for installation...')\n",
    "            time.sleep(3)\n",
    "        else:\n",
    "            raise ImportError('Failed to install pgmpy after multiple attempts')\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "from sklearn.preprocessing import LabelEncoder\n",
    "\n",
    "# Load Titanic dataset\n",
    "url = 'https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv'\n",
    "df = pd.read_csv(url)\n",
    "\n",
    "# Preprocess the data\n",
    "df['Age'].fillna(df['Age'].median(), inplace=True)\n",
    "df['Embarked'].fillna(df['Embarked'].mode()[0], inplace=True)\n",
    "\n",
    "# Create age groups\n",
    "df['AgeGroup'] = pd.cut(df['Age'], bins=[0, 12, 30, 50, 100], labels=['Child', 'Young', 'Adult', 'Elder'])\n",
    "\n",
    "# Select features for the Bayesian Network\n",
    "features = ['Pclass', 'Sex', 'AgeGroup', 'Survived']\n",
    "df_model = df[features].copy()\n",
    "\n",
    "# Label encode categorical variables\n",
    "le_dict = {}\n",
    "for col in df_model.columns:\n",
    "    le = LabelEncoder()\n",
    "    df_model[col] = le.fit_transform(df_model[col])\n",
    "    le_dict[col] = le\n",
    "\n",
    "# Create Bayesian Network structure\n",
    "model = BayesianNetwork([\n",
    "    ('Pclass', 'Survived'),\n",
    "    ('Sex', 'Survived'),\n",
    "    ('AgeGroup', 'Survived')\n",
    "])\n",
    "\n",
    "# Calculate CPDs\n",
    "cpd_pclass = TabularCPD(variable='Pclass', variable_card=3,\n",
    "                        values=[df_model['Pclass'].value_counts(normalize=True).values])\n",
    "\n",
    "cpd_sex = TabularCPD(variable='Sex', variable_card=2,\n",
    "                     values=[df_model['Sex'].value_counts(normalize=True).values])\n",
    "\n",
    "cpd_age = TabularCPD(variable='AgeGroup', variable_card=4,\n",
    "                     values=[df_model['AgeGroup'].value_counts(normalize=True).values])\n",
    "\n",
    "# Calculate survival probabilities\n",
    "survival_data = []\n",
    "for pclass in range(3):\n",
    "    for sex in range(2):\n",
    "        for age in range(4):\n",
    "            mask = (df_model['Pclass'] == pclass) & (df_model['Sex'] == sex) & (df_model['AgeGroup'] == age)\n",
    "            if mask.any():\n",
    "                prob_survival = df_model[mask]['Survived'].mean()\n",
    "            else:\n",
    "                prob_survival = 0.5\n",
    "            survival_data.append([1-prob_survival, prob_survival])\n",
    "\n",
    "cpd_survived = TabularCPD(\n",
    "    variable='Survived',\n",
    "    variable_card=2,\n",
    "    values=np.array(survival_data).T,\n",
    "    evidence=['Pclass', 'Sex', 'AgeGroup'],\n",
    "    evidence_card=[3, 2, 4]\n",
    ")\n",
    "\n",
    "# Add CPDs to model and validate\n",
    "model.add_cpds(cpd_pclass, cpd_sex, cpd_age, cpd_survived)\n",
    "model.check_model()\n",
    "\n",
    "# Create inference engine\n",
    "inference = VariableElimination(model)\n",
    "\n",
    "# Visualize network\n",
    "plt.figure(figsize=(10, 6))\n",
    "pos = {\n",
    "    'Pclass': (0, 0),\n",
    "    'Sex': (1, 0),\n",
    "    'AgeGroup': (2, 0),\n",
    "    'Survived': (1, -1)\n",
    "}\n",
    "model.draw(pos=pos)\n",
    "plt.title('Titanic Survival Bayesian Network')\n",
    "plt.show()\n",
    "\n",
    "# Function for survival prediction\n",
    "def predict_survival(pclass, sex, age_group):\n",
    "    evidence = {\n",
    "        'Pclass': le_dict['Pclass'].transform([pclass])[0],\n",
    "        'Sex': le_dict['Sex'].transform([sex])[0],\n",
    "        'AgeGroup': le_dict['AgeGroup'].transform([age_group])[0]\n",
    "    }\n",
    "    result = inference.query(variables=['Survived'], evidence=evidence)\n",
    "    return result.values[1]\n",
    "\n",
    "# Example predictions\n",
    "print('\\nSurvival Probability Examples:')\n",
    "examples = [\n",
    "    ('1st', 'female', 'Young'),\n",
    "    ('3rd', 'male', 'Adult'),\n",
    "    ('2nd', 'female', 'Child'),\n",
    "    ('1st', 'male', 'Elder')\n",
    "]\n",
    "\n",
    "for pclass, sex, age_group in examples:\n",
    "    prob = predict_survival(pclass, sex, age_group)\n",
    "    print(f'Passenger (Class: {pclass}, Sex: {sex}, Age: {age_group}) - Survival Probability: {prob:.2%}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "5a2aeb34",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-23T02:32:32.902363Z",
     "iopub.status.busy": "2025-02-23T02:32:32.901647Z",
     "iopub.status.idle": "2025-02-23T02:32:33.562541Z",
     "shell.execute_reply": "2025-02-23T02:32:33.561810Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAA/sAAAKACAYAAADD6miMAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAUO9JREFUeJzt3Xd43XXd//FX0qbpXrRAocyyZYlShuxZFHBAAcWfTEFxAm5lOLgVZOgtggMUb5SpAsoWpAjIEArIFsosUCjQRUfaJOf3R2ls6Era5MzH47q4LpqcnHy+WZ/rfb7f8zx1hUKhEAAAAKBq1Jd6AQAAAEDXMuwDAABAlTHsAwAAQJUx7AMAAECVMewDAABAlTHsAwAAQJUx7AMAAECVMewDAABAlTHsAwAAQJUx7APQZu21105dXd0S/0uSU089Nf3792/7mHnz5mXcuHGZNWtWl6/noosuSl1dXd54440Vup9Zs2bl5JNPzvrrr5/GxsaMGDEiRx11VCZNmtRFK12yww8/PJtuummX3d9FF12Utddee5m3eff3rn///hk9enSuu+66LltLV+nqr9HS7LLLLqmrq8vFF1+82HUcfvjhnbq/V155Jffdd18Xra7jOvJzAEBtM+wD0Oaee+7JSy+9lJdeeiljx47Nhhtu2Pbvl156KUlywgkn5D//+U/bx7z88svZdddd8/rrr3f5eg466KC89NJLGTp06Ardz9ixY3PBBRfk1FNPzSOPPJLf//73+fe//53tt99+hR9IWJZzzjknt956a7d+jiX597//3fa9u/POO7POOuvkIx/5SB5//PGSrGdJiv01GjRoUE4++eTMnTt3he/rV7/6Vb72ta91waoAoGsZ9gFos+qqq2bkyJEZOXJk+vbtm549e7b9e+TIkUmSgQMHZrXVVivKevr27ZuRI0emvn75t6sJEybk+uuvz89+9rMceuih2WCDDbL77rvnzjvvTEtLS84777wuXPGihgwZklVWWaVbP8eSjBgxou17t+WWW+Y3v/lNWltby+7sfrG/RkceeWTefvvt/PznPy/a5wSAYjPsA9ApC18+fPjhh2edddZJkqyzzjptl/on888qH3jggVljjTXS2NiYddddN2eddVa7+3n/+9+fhx9+OLvsskv69OmT0aNH55FHHmm7zbhx49rdZ5L84x//yNZbb53evXtnnXXWybnnnrvU9U6fPj1J0tra2u7tjY2NeeCBB3LyyScnSZ5//vnU1dXl+eefb3e7XXbZJaeeemrbbXr27JlJkyZlp512SmNjY0aOHJkTTzyx3ce88sor6dWrVyZPnpxTTz01u+yyS5Lk0EMPzfve975F1rjRRhvlz3/+c5Lkz3/+c3bdddcMHz48ffr0yVZbbZWbbrppqcfYUQu+lgs/DWNp36c77rgj9fX1mThxYrv7Ofjgg/OTn/wkyfwrOw4++OAMHjw4AwYMyF577dXue5gkl19+ebbccsv07t07q6yySo455phMmzat7f0Lf42SpLm5OWeccUa22mqrDBgwIAMHDsw+++yTCRMmtN1m7bXXzl//+td873vfy/DhwzNs2LB861vfSqFQWObXYeDAgTnppJNy2mmntf18LE6hUMgZZ5yRddZZJ42Njdl4443zi1/8ot3X87vf/W5uv/321NXV5fDDD89XvvKV7Ljjju3uZ9VVV80111zT9u+HHnqo7cGzJLnzzjuz0047ZeDAgVl99dVz8sknp6Wlpe39hx9+eH7wgx/kvPPOy9ChQ/ODH/xgsev9+Mc/nj322CPNzc3L/BoAUP0M+wAst3POOSd33313kuTuu+9uu9R/6tSp2XnnnTNgwIBcc801eeqpp3LmmWfm1FNPzbhx49o+ftq0aTnuuOPyta99LQ888EA23HDD7L///u0GnYU98sgj2XvvvbP99tvn4Ycfzg9/+MN84xvfyGWXXbbENW6yySZZeeWVc9xxx+VXv/pVXn311bb3DRs2bLmO+7jjjss+++yTxx57LAceeGCuuuqqdu+/5pprssMOO2T48OHt3j527NiMHz8+L7zwQtvbnnjiiUycODH77LNPxo0bl4MOOij77rtv7rjjjjzyyCM54IADcsABB2TmzJnLtdYFXn311Xz2s5/NiBEjMnbs2CTL/j594AMfyIgRI3LllVe23c/bb7+d66+/PgcddFCmTZuWnXfeOT169MhNN92Ue+65JxtssEF22WWXvPLKK0mS22+/PYccckgOPfTQ/Pvf/85ll12Wf/3rXzniiCOWuNbTTjstZ511Vr71rW/loYceyj//+c/0798/Rx11VLvbnXPOOZk8eXLuuOOO/OY3v8n555+f3/zmNx36enzmM5/JoEGDcvrppy/xNl/96ldz/vnn5yc/+UkeffTRnHLKKfnGN77RNvC/9NJLOf7447PtttvmpZdeyjnnnJMxY8bknnvuyYwZM5Ikjz76aF577bXceOONbfd74403Zs8990wy/wGtXXfdNXvttVfuv//+nHvuuTnvvPPy1a9+td1axo8fn9/85je56qqr8sUvfnGRtZ5yyil54IEHcuWVV6Znz54d+hoAUOUKALAYhx12WOE973nPIm//7W9/W1hrrbXa/v3cc88VkhSee+65trfNnDmzcNtttxXmzp3b7mPHjh1b+Na3vtV2P0kKN910U9v7X3/99UKSwmOPPVYoFAqF2267rbDwVnXQQQcVtthii3b3eeqppxZ23HHHpR7LuHHjCiNGjCgkKSQpbLDBBoUTTjih8OSTTy71OAqFQmHnnXcunHLKKe1uc9xxx7W9/8477ywkKYwfP77tbXvuuWfh3HPPLRQKhcIpp5xS2HnnnQuFQqEwe/bswoABAwpnn312221PO+20woEHHlgoFAqFSZMmFe6+++5F1j98+PDCzTff3PZ1W/jrvzgLvrb9+vUr9OvXr9DY2FhIUhg1alRhwoQJbbfryPfpC1/4QmGbbbZpe9/FF1/cdjzf/e53F/l+FAqFwmabbVY4+eSTC4VCoXDGGWcUBg0aVGhpaWl7/3PPPVe45ppr2v698NeoUCgUnnrqqcLjjz/e7j4fe+yxQn19fWHOnDmFQqFQWGuttQrbbbddu9scd9xxhbFjxy71a7Pw9/PSSy8t9O3bt/Dyyy8XCoX5P/OHHXZYoVAoFJ599tlCjx492n1fC4VC4ayzziqsueaaS1z7nDlzCv369StcffXVhUKhUPjJT35SWHvttQvrrLNOuzX84Q9/KBQKhcK2225b2G+//dp9josuuqjQq1evwmuvvda2rt69exdefPHFttss/HNwySWXFAYPHtzu5xkAnNkHoMv17ds373nPe/Ltb387o0ePzogRIzJw4MBcddVVmTx5ctvt+vXrlz322KPt3wvOtL/55puLvd9x48a1u9w7SY4//vj85S9/Wep6dt5557zwwgu54YYbcsIJJ6ShoSFnn312Nttss7bL5zvj4IMPbvv/7bffPquvvnr+9Kc/JZl/tvz222/PRz/60UU+rnfv3tlvv/3abpskV111VQ444IAkySqrrJI+ffrkiCOOyKabbprhw4dnwIABeeONN9p93Trqtttuy0MPPZRHH300d9xxR7bYYovsuuuubVHCjnyfDjrooNx7771tVyNccsklbcd/00035bHHHkv//v3b/ff444/nwQcfTJJst912mT59evbee+/83//9Xx599NGsueaa2X///Ze47g022CBPP/10PvzhD2e99dbL0KFDs/XWW6e1tbXdz8aHP/zhdh83bNiwJf7sLM7BBx+cjTfeuO1pGgu75ZZb0tLSkh133LHdsX3729/Oiy++mLfeemux99nY2JhddtklN998c5Lk1ltvzUknnZRXXnklTz31VGbMmJG77747e+yxR2bNmpV77703u+++e7v7GDNmTObOndvuKpjtttsua6yxxiKf7+67786RRx6Z973vfdlwww07fOwAVD/DPgBdbvr06dluu+1y5ZVX5sgjj8zVV1+dBx54IPvtt1+7AvpKK63ULr634DnlS7qM/6233lok5DZw4MAMHjx4mWtqaGjImDFjctZZZ+XRRx/Nvffem5VXXjlf+MIXOn18Cz/fuq6uLgceeGDbgwbXXntt3v/+9y8xYjh27NjcfffdmTRpUiZOnJhHH300H/rQh5Ik999/f7bbbrtMmDAhp5xySm6++eY8+OCDGTFixHKV49dZZ52st956WW+99bLDDjvk0ksvTV1dXb7zne8k6dj36QMf+EBWX331XHHFFXnjjTdy22235cADD0ySTJ48Ofvvv38eeuihdv89+eSTOf/885MkO+ywQy6//PLMmzcvxxxzTDbbbLMMGzYsv/zlL5e47vPOOy8f/vCHM3To0Jx33nm544472qKCC38dVl555XYfV1dXt8SfncWpq6vLGWeckd/+9rd56qmn2r1v8uTJqa+vz/jx49sd2yOPPJKnn346AwcOXOL9jhkzJjfddFNaWlpyxx13ZN99981OO+2UG2+8MbfeemvbU0umTp2aQqGwyHEsePWJ1157re1tC//MLTB9+vQceOCB+fWvf5277rord911V4ePHYDq50ldAHS5yy+/PBMmTMjjjz+ejTfeuO3tM2bMaDckvTu+tyzDhw/PlClT2r1t2rRpaW5uzkorrbTYj7nrrrvS1NSU3Xbbrd3bR48enRNPPDEnnHBC3n777fTo0SPJoiG/xZ0pfverA4wdOzY//elP88QTT+Tqq69uO1O/OGPGjEm/fv1y1VVXpaWlJXvuuWcGDBiQZP5z0FdaaaX87W9/S2NjY5L5sbolnUXurF69emX06NG5//77k3Ts+7TgwYwrrrgi/fv3z4477tjWIlhllVUyffr0rLfeekv9vGPHjs3YsWMzd+7cPPTQQzn33HPz2c9+NjvuuGM22WSTRW5/2mmn5aCDDspvf/vbtrctbpDt7M/P4uy2227ZY4898s1vfrPdz+Yqq6yS1tbW9OvXL6uvvnqn7nPMmDH5whe+kCuuuCKrr756Vl555YwZMyY33nhj1lprrbbn6w8bNix1dXWL/EwvuPJi4Z/pxb0ixZQpU3LyySfnk5/8ZO65556cdNJJ+fvf/96ptQJQvZzZB2CF9O3bN0kye/bstrdNmzYtPXr0yPrrr9/2tueeey633377Cn2u3XbbLbfccku7t5155pltZ8YX55///Gc+9alPLXZgfuWVV7LKKqukf//+WXnlldOrV6925fnnn3++Q69Jv+BS/ksuuSQ33XRTPvaxjy3xtgsu5f/zn//c7hL+ZP7XbdSoUW2DfpJcdtllmTNnzjLX0FEvvPBC27De0e/TQQcdlPvvvz/nnHNODjnkkLa377nnnvnHP/6RSZMmtb2tubk5m2++eX7/+98nSX75y1/moosuSvLfBxvOPffcFAqFJX5tp02b1u7BhyTtBv+udvrpp+eaa67Jfffd1/a23XffPfX19bn88svb3fZ73/teu5+3vn37tvvZT5L11lsvo0aNykknndR2if4+++yT22+/Pddff33bsN+rV6/ssMMOueGGG9p9/A033JCGhoZFnrLybquvvnq+/OUvJ0m+/vWv56677mp36T8Atc2wD8AKWfCyZ+eff34mTZqUKVOmZM8990xra2tOOOGEPPnkk/n73/+eAw44IB/4wAc6dZn1u33961/Po48+mhNPPDFPPfVULr300px99tltA8/ifP7zn8+oUaOy3Xbb5Q9/+EOeeuqp3HffffnOd76Tc845p+352o2Njdl7771zxhlnZOrUqZkwYUKOPPLIbLXVVstc14Kz32eeeWY23HDDtpcmXJKxY8dm3Lhxufvuu9s9d33vvffOXXfdlQsvvDDPPPNMfv/73+d///d/s8466yzX1+3VV1/NxIkTM3HixDz88MP54he/mPvuuy/HHHNMknT4+7Tg+eIvvPBCuxbB5z73uQwbNiwHHHBA7rzzzjz66KP51Kc+lWnTprUd14ABA3LcccfljDPOyL///e+MHz8+xx9/fPr27Zvtt99+sevee++9c+GFF+bmm2/Of/7zn5xyyil5+eWXkyz5KR4rYvPNN88nP/nJPPHEE21vW3vttXP00Ufnu9/9bi666KL85z//yQUXXJDTTz+93asCbLLJJhk/fnzGjRuXl156qW19Y8aMyYQJE9quKNl4442z8sorZ/Lkye1emu873/lOrrvuupxyyil5+umnc9VVV+Ub3/hGvvKVryzxqSALLFzdX2ONNXL44YfnpJNO6pKvCQCVz7APwAqpq6vLz372s1x++eVZd911c9lll2WLLbbIxRdfnOuvvz5bbLFFTjjhhJx++unZfvvt2y5RXh6bbbZZbrjhhtx+++3ZYost8u1vfztnn312u7PN79anT5/ccMMNOeyww/LDH/4wW221Vfbaa6/cfffdueqqq/KZz3ym7bbnn39+WlpassYaa2T//ffPCSeckPe85z0dWtvYsWMzZ86cpV7Cv8CYMWPSp0+f7LjjjhkyZEjb2z/3uc/lxBNPzDe/+c22r+Hll1+eESNGLNfXbfPNN88aa6yRNdZYI9tuu23uuOOOXH755W0De0e/T3V1ddlvv/2y1157tVvvSiutlH/84x9ZaaWV8sEPfjA77LBDkuSBBx5ouyT+E5/4RM4///xccsklGT16dNvL8t1+++1LHGZ/+ctfZptttsnHPvaxbLvttpk0aVLbyyuuyM/P0nz/+99P7969273t3HPPzZe+9KWcdNJJ2XzzzfOLX/wi11xzTbsrN/bZZ58ceOCB+eAHP5jNN98806dPTzL/e9yjR4/svPPObbcdM2ZMdtxxx3afZ6+99soVV1yRP/7xj9l0001z4okn5utf/3pOO+20Th/DN7/5zdx7771tcUAAaltdoVAolHoRAEB523nnnXPMMcfk0EMPLfVSAIAOEOgDABZrxowZmTRpUq677ro8+eSTS20RAADlxbAPACzW448/nt133z2rrLJK/vCHP6RPnz6lXhIA0EEu4wcAAIAqI9AHAAAAVcawDwAAAFXGsA8AAABVxrAPAAAAVcawDwAAAFXGsA8AAABVxrAPAAAAVcawDwAAAFXGsA8AAABVxrAPAAAAVcawDwAAAFXGsA8AAABVxrAPAAAAVcawDwAAAFXGsA8AAABVxrAPAAAAVcawDwAA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",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Survival Probability by Class:\n",
      "Pclass\n",
      "1    0.629630\n",
      "2    0.472826\n",
      "3    0.242363\n",
      "Name: Survived, dtype: float64\n",
      "\n",
      "Survival Probability by Sex:\n",
      "Sex\n",
      "female    0.742038\n",
      "male      0.188908\n",
      "Name: Survived, dtype: float64\n",
      "\n",
      "Survival Probability by Age Group:\n",
      "AgeGroup\n",
      "Child    0.579710\n",
      "Young    0.344294\n",
      "Adult    0.423237\n",
      "Elder    0.343750\n",
      "Name: Survived, dtype: float64\n",
      "\n",
      "Survival Probability Examples:\n",
      "Passenger (Class: 1, Sex: female, Age: Young) - Survival Probability: 97.67%\n",
      "Passenger (Class: 3, Sex: male, Age: Adult) - Survival Probability: 12.68%\n",
      "Passenger (Class: 2, Sex: female, Age: Child) - Survival Probability: 100.00%\n",
      "Passenger (Class: 1, Sex: male, Age: Elder) - Survival Probability: 19.23%\n",
      "\n",
      "Model Accuracy: 81.37%\n"
     ]
    }
   ],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "from sklearn.preprocessing import LabelEncoder\n",
    "import matplotlib.pyplot as plt\n",
    "import networkx as nx\n",
    "\n",
    "# Load Titanic dataset\n",
    "url = 'https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv'\n",
    "df = pd.read_csv(url)\n",
    "\n",
    "# Preprocess the data\n",
    "df['Age'].fillna(df['Age'].median(), inplace=True)\n",
    "df['Embarked'].fillna(df['Embarked'].mode()[0], inplace=True)\n",
    "\n",
    "# Create age groups\n",
    "df['AgeGroup'] = pd.cut(df['Age'], bins=[0, 12, 30, 50, 100], labels=['Child', 'Young', 'Adult', 'Elder'])\n",
    "\n",
    "# Select features\n",
    "features = ['Pclass', 'Sex', 'AgeGroup', 'Survived']\n",
    "df_model = df[features].copy()\n",
    "\n",
    "# Calculate probabilities manually\n",
    "def calculate_conditional_probability(data, target, features):\n",
    "    \"\"\"Calculate conditional probability P(target|features)\"\"\"\n",
    "    grouped = data.groupby(features)[target].mean()\n",
    "    return grouped\n",
    "\n",
    "# Calculate individual probabilities\n",
    "P_survival_given_class = calculate_conditional_probability(df_model, 'Survived', ['Pclass'])\n",
    "P_survival_given_sex = calculate_conditional_probability(df_model, 'Survived', ['Sex'])\n",
    "P_survival_given_age = calculate_conditional_probability(df_model, 'Survived', ['AgeGroup'])\n",
    "\n",
    "# Calculate joint probabilities\n",
    "P_survival_joint = calculate_conditional_probability(df_model, 'Survived', ['Pclass', 'Sex', 'AgeGroup'])\n",
    "\n",
    "# Visualize the network structure\n",
    "G = nx.DiGraph()\n",
    "nodes = ['Pclass', 'Sex', 'AgeGroup', 'Survived']\n",
    "G.add_nodes_from(nodes)\n",
    "edges = [('Pclass', 'Survived'), ('Sex', 'Survived'), ('AgeGroup', 'Survived')]\n",
    "G.add_edges_from(edges)\n",
    "\n",
    "plt.figure(figsize=(10, 6))\n",
    "pos = {\n",
    "    'Pclass': (0, 0),\n",
    "    'Sex': (1, 0),\n",
    "    'AgeGroup': (2, 0),\n",
    "    'Survived': (1, -1)\n",
    "}\n",
    "nx.draw(G, pos, with_labels=True, node_color='lightblue', \n",
    "        node_size=2000, font_size=10, font_weight='bold',\n",
    "        arrows=True, edge_color='gray')\n",
    "plt.title('Titanic Survival Bayesian Network')\n",
    "plt.show()\n",
    "\n",
    "# Function to predict survival probability\n",
    "def predict_survival_probability(pclass, sex, age_group):\n",
    "    try:\n",
    "        prob = P_survival_joint.loc[pclass, sex, age_group]\n",
    "    except KeyError:\n",
    "        # If combination not found in data, use average of individual probabilities\n",
    "        p1 = P_survival_given_class.loc[pclass]\n",
    "        p2 = P_survival_given_sex.loc[sex]\n",
    "        p3 = P_survival_given_age.loc[age_group]\n",
    "        prob = (p1 + p2 + p3) / 3\n",
    "    return prob\n",
    "\n",
    "# Print probability tables\n",
    "print(\"\\nSurvival Probability by Class:\")\n",
    "print(P_survival_given_class)\n",
    "print(\"\\nSurvival Probability by Sex:\")\n",
    "print(P_survival_given_sex)\n",
    "print(\"\\nSurvival Probability by Age Group:\")\n",
    "print(P_survival_given_age)\n",
    "\n",
    "# Example predictions\n",
    "print(\"\\nSurvival Probability Examples:\")\n",
    "examples = [\n",
    "    (1, 'female', 'Young'),\n",
    "    (3, 'male', 'Adult'),\n",
    "    (2, 'female', 'Child'),\n",
    "    (1, 'male', 'Elder')\n",
    "]\n",
    "\n",
    "for pclass, sex, age_group in examples:\n",
    "    prob = predict_survival_probability(pclass, sex, age_group)\n",
    "    print(f\"Passenger (Class: {pclass}, Sex: {sex}, Age: {age_group}) - \"\n",
    "          f\"Survival Probability: {prob:.2%}\")\n",
    "\n",
    "# Calculate and print overall model accuracy using these probabilities\n",
    "def calculate_prediction_accuracy():\n",
    "    predictions = []\n",
    "    for _, row in df_model.iterrows():\n",
    "        prob = predict_survival_probability(row['Pclass'], row['Sex'], row['AgeGroup'])\n",
    "        pred = 1 if prob >= 0.5 else 0\n",
    "        predictions.append(pred)\n",
    "    \n",
    "    accuracy = np.mean(predictions == df_model['Survived'])\n",
    "    return accuracy\n",
    "\n",
    "accuracy = calculate_prediction_accuracy()\n",
    "print(f\"\\nModel Accuracy: {accuracy:.2%}\")"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
